﻿using ChessServer.Common;
using ChessServer.Log;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ChessServer.Net {
    public class TcpSocketServer : INetServer {

        private Socket listenSocket;
        private BufferManager bufferManager;
        private SocketSettings socketSettings = null;
        protected RequestHandler requestHandler;
        private ConcurrentStack<SocketAsyncEventArgs> ioEventArgsPool;

        public ConcurrentQueue<ConnectionEventArgs> _listMessage = new ConcurrentQueue<ConnectionEventArgs> ();
        private Thread _messageThread;
        static bool messagethreadout = false;


        public ChessServer.Threading.SmartThreadPool MessageProcessorPool {
            get; set;
        }

        private static TcpSocketServer _instance;

        public static TcpSocketServer instance {
            get {
                if ( _instance == null ) {
                    _instance = new TcpSocketServer ();
                }
                return _instance;
            }
        }
        /// <summary>
        /// 连接事件
        /// </summary>
        public event ConnectionEventHandler Connected;
        private void OnConnected ( ConnectionEventArgs e ) {
            if ( Connected != null ) {
                Connected ( this, e );
            }
        }
        /// <summary>
        /// 握手事件
        /// </summary>
        public event ConnectionEventHandler Handshaked;
        private void OnHandshaked ( ConnectionEventArgs e ) {
            if ( Handshaked != null ) {
                Handshaked ( this, e );
            }
        }
        /// <summary>
        /// 断开连接事件
        /// </summary>
        public event ConnectionEventHandler Disconnected;
        private void OnDisconnected ( ConnectionEventArgs e ) {
            if ( Disconnected != null ) {
                Disconnected ( this, e );
            }
        }

        /// <summary>
        /// 接收到数据包事件
        /// </summary>
        public event ConnectionEventHandler DataReceived;
        private void OnDataReceived ( ConnectionEventArgs e ) {
            if ( DataReceived != null ) {
                DataReceived ( this, e );
            }
        }

        public event Action<ExSocket, int> OnClosedStatus;
        private void DoClosedStatus ( ExSocket socket, int statusCode ) {
            Action<ExSocket, int> handler = OnClosedStatus;
            if ( handler != null )
                handler ( socket, statusCode );
        }
        /// <summary>
        /// 
        /// </summary>
        public event ConnectionEventHandler OnPing;
        private void DoPing ( ConnectionEventArgs e ) {
            ConnectionEventHandler handler = OnPing;
            if ( handler != null )
                handler ( this, e );
        }

        /// <summary>
        /// 
        /// </summary>
        public event ConnectionEventHandler OnPong;
        private void DoPong ( ConnectionEventArgs e ) {
            ConnectionEventHandler handler = OnPong;
            if ( handler != null )
                handler ( this, e );
        }

        internal int Init () {
            socketSettings = new SocketSettings ( ConfigUtils.GetSetting ( "MaxConnections", 10000 )
                , ConfigUtils.GetSetting ( "Backlog", 1000 )
                , ConfigUtils.GetSetting ( "MaxAcceptOps", 1000 )
                , ConfigUtils.GetSetting ( "BufferSize", 1024 * 10 )
                , new IPEndPoint ( IPAddress.Any, ConfigUtils.GetSetting ( "Game.Port", 6101 ) )
                , ConfigUtils.GetSetting ( "ExpireInterval", 600 ) * 1000
                , ConfigUtils.GetSetting ( "ExpireTime", 3600 ) * 1000 );

            this.requestHandler = new RequestHandler(new MessageHandler ());
            this.bufferManager = new BufferManager ( this.socketSettings.BufferSize * this.socketSettings.NumOfSaeaForRecSend, this.socketSettings.BufferSize );

            this.ioEventArgsPool = new ConcurrentStack<SocketAsyncEventArgs> ();

            this.bufferManager.InitBuffer ();

            SocketAsyncEventArgs ioEventArgs;
            for ( int i = 0; i < this.socketSettings.NumOfSaeaForRecSend; i++ ) {
                ioEventArgs = new SocketAsyncEventArgs ();
                this.bufferManager.SetBuffer ( ioEventArgs );
                ioEventArgs.Completed += new EventHandler<SocketAsyncEventArgs> ( IO_Completed );
                DataToken dataToken = new DataToken ();
                dataToken.bufferOffset = ioEventArgs.Offset;
                ioEventArgs.UserToken = dataToken;
                this.ioEventArgsPool.Push ( ioEventArgs );
            }
            _messageThread = new Thread ( MessageUpdate );
            _messageThread.Name = "MessageThread";
            _messageThread.Start ( this );
            _messageThread.Priority = ThreadPriority.Highest;
            return 0;
        }

        private static void MessageUpdate ( object o ) {
            var listener = ( TcpSocketServer ) o;
            var tick = Environment.TickCount;
            while ( !messagethreadout ) {
                try {
                    var now = Environment.TickCount;
                    if ( listener._listMessage.Count < 1 ) {
                        Thread.Sleep ( 10 );
                        //_messageWaitEvent.WaitOne(-1);
                    }
                    else {
                        ConnectionEventArgs message;
                        while ( listener._listMessage.TryDequeue ( out message ) ) {
                            listener.OnDataReceived ( message );
                        }
                    }
                    tick = now;
                }
                catch ( Exception ex ) {
                    OurDebug.LogException ( ex );
                }
            }
        }

        internal static int Stop () {
            throw new NotImplementedException ();
        }

        private SocketAsyncEventArgs CreateAcceptEventArgs () {
            SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs ();
            acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs> ( Accept_Completed );
            return acceptEventArg;
        }
        /// <summary>
        /// Starts the listen.
        /// </summary>
        public void StartListen () {
            OurDebug.LogFormat ( "start listen {0}", socketSettings.LocalEndPoint );
            listenSocket = new Socket ( this.socketSettings.LocalEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp );
            listenSocket.SetSocketOption ( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true );
            listenSocket.Bind ( this.socketSettings.LocalEndPoint );
            listenSocket.Listen ( socketSettings.Backlog );
            OurDebug.LogFormat ( "listening....." );
            requestHandler.Bind ( this );
            PostAccept ( null );
        }

        private void PostAccept ( SocketAsyncEventArgs acceptEventArgs ) {
            try {
                acceptEventArgs = acceptEventArgs ?? CreateAcceptEventArgs ();
                bool willRaiseEvent = listenSocket.AcceptAsync ( acceptEventArgs );
                if ( !willRaiseEvent ) {
                    ProcessAccept ( acceptEventArgs );
                }
            }
            catch ( Exception ex ) {
                OurDebug.LogErrorFormat ( "Post accept listen error:{0}", ex );
            }
        }

        private void Accept_Completed ( object sender, SocketAsyncEventArgs acceptEventArgs ) {
            try {
                ProcessAccept ( acceptEventArgs );
            }
            catch ( Exception ex ) {
                OurDebug.LogErrorFormat ( "AcceptCompleted method error:{0}", ex );

                if ( acceptEventArgs.AcceptSocket != null ) {
                    try {
                        acceptEventArgs.AcceptSocket.Close ();
                    }
                    catch {
                    }
                    acceptEventArgs.AcceptSocket = null;
                }
            }
        }

        
        private void ProcessAccept ( SocketAsyncEventArgs acceptEventArgs ) {
            //var watch = RunTimeWatch.StartNew("ProcessAccept");
            try {
                if ( acceptEventArgs.SocketError != SocketError.Success ) {
                    HandleBadAccept ( acceptEventArgs );
                    OurDebug.Log ( "OnConnected HandleBadAccept" );
                }
                else {
                    //watch.Check("Interlocked.Increment");
                    SocketAsyncEventArgs ioEventArgs;
                    if ( !ioEventArgsPool.TryPop ( out ioEventArgs ) ) {
                        OurDebug.Log ( "ioEventArgsPool not enough!" );
                        return;
                    }
                    ioEventArgs.AcceptSocket = acceptEventArgs.AcceptSocket;
                    var dataToken = ( DataToken ) ioEventArgs.UserToken;
                    ioEventArgs.SetBuffer ( dataToken.bufferOffset, socketSettings.BufferSize );
                    var exSocket = new ExSocket ( ioEventArgs.AcceptSocket );
                    exSocket.LastAccessTime = DateTime.Now;
                    dataToken.Socket = exSocket;
                    acceptEventArgs.AcceptSocket = null;

                    try {
                        //watch.Check("save socket,pop ioevent");
                        OnConnected ( new ConnectionEventArgs { Socket = exSocket } );
                        OurDebug.LogFormat ( "OnConnected " );
                    }
                    catch ( Exception ex ) {
                        OurDebug.LogErrorFormat ( "OnConnected error:{0}", ex );
                    }
                    //watch.Check("OnConnected");
                    PostReceive ( ioEventArgs );
                }

            }
            finally {
                //watch.Flush(10);
                if ( acceptEventArgs != null && listenSocket != null )
                    PostAccept ( acceptEventArgs );
                else {
                    OurDebug.LogErrorFormat ( "ProcessAccept error acceptEventArgs or listenSocket is empty" );
                }
            }
        }

        private void IO_Completed ( object sender, SocketAsyncEventArgs ioEventArgs ) {
            DataToken ioDataToken = ( DataToken ) ioEventArgs.UserToken;
            try {
                ioDataToken.Socket.LastAccessTime = DateTime.Now;
                switch ( ioEventArgs.LastOperation ) {
                    case SocketAsyncOperation.Receive:
                        ProcessReceive ( ioEventArgs );
                        break;
                    case SocketAsyncOperation.Send:
                        ProcessSend ( ioEventArgs );
                        break;

                    default:
                        throw new ArgumentException ( "The last operation completed on the socket was not a receive or send" );
                }
            }
            catch ( ObjectDisposedException ) {
                //modify disposed error ignore log
                //logger.Error(string.Format("IO_Completed error:{0}", error));
                ReleaseIOEventArgs ( ioEventArgs );
            }
            catch ( Exception ex ) {
                OurDebug.LogErrorFormat ( "IP {0} IO_Completed unkown error:{1}", ( ioDataToken != null && ioDataToken.Socket != null ? ioDataToken.Socket.RemoteEndPoint.ToString () : "" ), ex );
            }
        }

        private void ReleaseIOEventArgs ( SocketAsyncEventArgs ioEventArgs ) {
            if ( ioEventArgs == null )
                return;

            var dataToken = ( DataToken ) ioEventArgs.UserToken;
            if ( dataToken != null ) {
                dataToken.Reset ( true );
                dataToken.Socket = null;
            }
            ioEventArgs.AcceptSocket = null;
            ioEventArgsPool.Push ( ioEventArgs );
        }
        /// <summary>
        /// 投递接收数据请求
        /// </summary>
        /// <param name="ioEventArgs"></param>
        private void PostReceive ( SocketAsyncEventArgs ioEventArgs ) {
            if ( ioEventArgs.AcceptSocket == null )
                return;

            bool willRaiseEvent = ioEventArgs.AcceptSocket.ReceiveAsync ( ioEventArgs );

            if ( !willRaiseEvent ) {
                ProcessReceive ( ioEventArgs );
            }
        }

        /// <summary>
        /// 处理数据接收回调
        /// </summary>
        /// <param name="ioEventArgs"></param>
        private void ProcessReceive ( SocketAsyncEventArgs ioEventArgs ) {
            DataToken dataToken = ( DataToken ) ioEventArgs.UserToken;
            if ( ioEventArgs.BytesTransferred == 0 ) {
                //对方主动关闭socket
                //if (logger.IsDebugEnabled) logger.Debug("对方关闭Socket");
                Closing ( ioEventArgs, OpCode.Empty );
                return;
            }

            if ( ioEventArgs.SocketError != SocketError.Success ) {//Socket错误
                OurDebug.LogFormat ( "IP {0} ProcessReceive:{1}", ( dataToken != null ? dataToken.Socket.RemoteEndPoint.ToString () : "" ), ioEventArgs.SocketError );
                Closing ( ioEventArgs );
                return;
            }
            ExSocket exSocket = dataToken == null ? null : dataToken.Socket;
            List<DataMessage> messages;
            bool hasHandshaked;
            bool needPostAnother = requestHandler.TryReceiveMessage ( ioEventArgs, out messages, out hasHandshaked );
            if ( hasHandshaked ) {
                OnHandshaked ( new ConnectionEventArgs { Socket = exSocket } );
            }
            //modify reason:数据包接收事件触发乱序
            if ( messages != null ) {
                foreach ( var message in messages ) {
                    try {
                        switch ( message.opcode ) {
                            case OpCode.Close:
                                var statusCode = requestHandler.MessageProcessor != null
                                    ? requestHandler.MessageProcessor.GetCloseStatus ( message.data )
                                    : OpCode.Empty;
                                if ( statusCode != OpCode.Empty ) {
                                    DoClosedStatus ( exSocket, statusCode );
                                }
                                Closing ( ioEventArgs, OpCode.Empty );
                                needPostAnother = false;
                                break;
                            case OpCode.Ping:
                                DoPing ( new ConnectionEventArgs { Socket = exSocket, Message = message } );
                                break;
                            case OpCode.Pong:
                                DoPong ( new ConnectionEventArgs { Socket = exSocket, Message = message } );
                                break;
                            default:
                                //lock (_listMessage)
                                //{
                                _listMessage.Enqueue ( new ConnectionEventArgs { Socket = exSocket, Message = message } );
                                //_messageWaitEvent.Set();
                                //}
                                //OnDataReceived(new ConnectionEventArgs { Socket = exSocket, Message = message });
                                break;
                        }
                    }
                    catch ( Exception ex ) {
                        OurDebug.LogErrorFormat ( "OnDataReceived error:{0}", ex );
                    }
                }
            }
            if ( needPostAnother ) {
                PostReceive ( ioEventArgs );
                //是否需要关闭连接
                if ( exSocket.IsClosed ) {
                    ResetSAEAObject ( ioEventArgs );
                }
            }
        }

        /// <summary>
        /// 不走队列，直接发。
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="result"></param>
        private void PostSendUnDequeue ( ExSocket socket, SocketAsyncResult result ) {
#if EventArgs
            var ioEventArgs = ioEventArgsPool.Pop();
            if(ioEventArgs == null)
            {
                OurDebug.LogError("ioEventArgsPool 用完了。。。");
                return;
            }
            ioEventArgs.AcceptSocket = socket.WorkSocket;
            DataToken dataToken = (DataToken)ioEventArgs.UserToken;
            dataToken.Socket = socket;
            dataToken.AsyncResult = result;
            dataToken.byteArrayForMessage = result.Data;
            dataToken.messageLength = result.Data.Length;
            try
            {
                PostSend(ioEventArgs);
            }
            catch (Exception ex)
            {
                dataToken.ResultCallback(ResultCode.Error, ex);
                ReleaseIOEventArgs(ioEventArgs);
                //socket.ResetSendFlag();
                OurDebug.LogError("PostSendUnDequeue exception");
            }
#else
            try {
                PostSend ( socket, result );
            }
            catch ( Exception ex ) {
                result.Error = ex;
                result.Callback ();
                //socket.ResetSendFlag();
                OurDebug.LogError ( "PostSendUnDequeue exception" );
            }

#endif
        }

        private void TryDequeueAndPostSend ( ExSocket socket, SocketAsyncEventArgs ioEventArgs ) {
            bool isOwner = ioEventArgs == null;
            SocketAsyncResult result;
            if ( socket.TryDequeue ( out result ) ) {
                if ( ioEventArgs == null ) {
                    if ( !ioEventArgsPool.TryPop ( out ioEventArgs ) ) {
                        OurDebug.LogError ( "ioEventArgsPool empty" );
                        return;
                    }
                    ioEventArgs.AcceptSocket = socket.WorkSocket;
                }
                DataToken dataToken = ( DataToken ) ioEventArgs.UserToken;
                dataToken.Socket = socket;
                dataToken.AsyncResult = result;
                dataToken.byteArrayForMessage = result.Data;
                dataToken.messageLength = result.Data.Length;
                try {
                    PostSend ( ioEventArgs );
                }
                catch ( Exception ex ) {
                    dataToken.ResultCallback ( ResultCode.Error, ex );
                    if ( isOwner )
                        ReleaseIOEventArgs ( ioEventArgs );
                    //socket.ResetSendFlag();
                }
            }
            else {
                ReleaseIOEventArgs ( ioEventArgs );
                //socket.ResetSendFlag();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public void PostSend ( ExSocket socket, byte [] data, int offset, int count ) {
            PostSend ( socket, OpCode.Binary, data, offset, count );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="opCode"></param>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public void PostSend ( ExSocket socket, sbyte opCode, byte [] data, int offset, int count ) {
            PostSend ( socket, opCode, data, offset, count, result => {
            } );
        }

        /// <summary>
        /// Posts the send.
        /// </summary>
        /// <param name="socket">Socket.</param>
        /// <param name="opCode"></param>
        /// <param name="data">Data.</param>
        /// <param name="offset">Offset.</param>
        /// <param name="count">Count.</param>
        /// <param name="callback"></param>
        public void PostSend ( ExSocket socket, sbyte opCode, byte [] data, int offset, int count, Action<SocketAsyncResult> callback, string debuguserid = "" ) {
            byte [] buffer = requestHandler.MessageProcessor.BuildMessagePack ( socket, opCode, data, offset, count );
            SendAsync ( socket, buffer, callback, debuguserid );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        public void Ping ( ExSocket socket ) {
            byte [] data = Encoding.UTF8.GetBytes ( "ping" );
            PostSend ( socket, OpCode.Ping, data, 0, data.Length );
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        public void Pong ( ExSocket socket ) {
            byte [] data = Encoding.UTF8.GetBytes ( "pong" );
            PostSend ( socket, OpCode.Pong, data, 0, data.Length );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="reason"></param>
        public void CloseHandshake ( ExSocket socket, string reason ) {
            requestHandler.SendCloseHandshake ( socket, OpCode.Close, reason );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="buffer"></param>
        /// <param name="callback"></param>
        internal protected bool SendAsync ( ExSocket socket, byte [] buffer, Action<SocketAsyncResult> callback, string debuguserid = "" ) {
            if ( !string.IsNullOrEmpty ( debuguserid ) ) {
                OurDebug.LogFormat ( string.Format ( "_usermsgwatch userid:{0} SendAsync buffer.Length({1}) <= this.socketSettings.BufferSize({2}):", debuguserid, buffer.Length, socketSettings.BufferSize ) );
                socket.watchuserid = debuguserid;
            }
            else {
                socket.watchuserid = "";
            }
            if ( buffer.Length <= this.socketSettings.BufferSize ) {
                PostSendUnDequeue ( socket, new SocketAsyncResult ( buffer ) { Socket = socket, ResultCallback = callback } );
                return true;
            }
            else {
                socket.Enqueue ( buffer, callback );
                //return await Task.Run(() =>
                //{
                //if (socket.TrySetSendFlag())
                {
                    try {
                        TryDequeueAndPostSend ( socket, null );
                        return true;
                    }
                    catch ( Exception ex ) {
                        //socket.ResetSendFlag();
                        OurDebug.LogErrorFormat ( "SendAsync {0} error:{1}", socket.RemoteEndPoint, ex );
                    }
                }
                //});
            }
            return false;
        }

        private void PostSend ( ExSocket socket, SocketAsyncResult result ) {
            Task.Run ( delegate {
                try {
                    var sentcount = socket.WorkSocket.Send ( result.Data, result.Data.Length, SocketFlags.None );
                    result.Result = ResultCode.Success;
                }
                catch ( Exception ex ) {
                    if ( ex is ObjectDisposedException )
                        result.Result = ResultCode.Close;
                    else
                        result.Result = ResultCode.Error;
                }
                result.Callback ();
            } );
        }

        private void PostSend ( SocketAsyncEventArgs ioEventArgs ) {
            DataToken dataToken = ( DataToken ) ioEventArgs.UserToken;
            if ( !string.IsNullOrEmpty ( dataToken.Socket.watchuserid ) ) {
                OurDebug.LogFormat ( string.Format ( "_usermsgwatch userid:{0} SetBuffer dataToken.messageLength:{1} messageBytesDone:{2} bufferOffset:{3}", dataToken.Socket.watchuserid, dataToken.messageLength, dataToken.messageBytesDone, dataToken.bufferOffset ) );
            }
            if ( dataToken.messageLength - dataToken.messageBytesDone <= this.socketSettings.BufferSize ) {
                ioEventArgs.SetBuffer ( dataToken.bufferOffset, dataToken.messageLength - dataToken.messageBytesDone );
                Buffer.BlockCopy ( dataToken.byteArrayForMessage, dataToken.messageBytesDone, ioEventArgs.Buffer, dataToken.bufferOffset, dataToken.messageLength - dataToken.messageBytesDone );
            }
            else {
                ioEventArgs.SetBuffer ( dataToken.bufferOffset, this.socketSettings.BufferSize );
                Buffer.BlockCopy ( dataToken.byteArrayForMessage, dataToken.messageBytesDone, ioEventArgs.Buffer, dataToken.bufferOffset, this.socketSettings.BufferSize );
            }

            var willRaiseEvent = ioEventArgs.AcceptSocket.SendAsync ( ioEventArgs );
            if ( !willRaiseEvent ) {
                ProcessSend ( ioEventArgs );
            }
        }

        private void ProcessSend ( SocketAsyncEventArgs ioEventArgs ) {
            DataToken dataToken = ( DataToken ) ioEventArgs.UserToken;
            if ( !string.IsNullOrEmpty ( dataToken.Socket.watchuserid ) ) {
                OurDebug.LogFormat ( string.Format ( "_usermsgwatch userid:{0} ProcessSend ioEventArgs.SocketError:{1} BytesTransferred:{2} messageBytesDone:{3}", dataToken.Socket.watchuserid, ioEventArgs.SocketError, ioEventArgs.BytesTransferred, dataToken.messageBytesDone ) );
            }
            if ( ioEventArgs.SocketError == SocketError.Success ) {
                dataToken.messageBytesDone += ioEventArgs.BytesTransferred;
                if ( dataToken.messageBytesDone != dataToken.messageLength ) {
                    PostSend ( ioEventArgs );
                }
                else {
                    dataToken.ResultCallback ( ResultCode.Success );
                    dataToken.Reset ( true );
                    TryDequeueAndPostSend ( dataToken.Socket, ioEventArgs );
                }
            }
            else {
                dataToken.ResultCallback ( ResultCode.Close );
                //dataToken.Socket.ResetSendFlag();
                Closing ( ioEventArgs );
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ioEventArgs"></param>
        /// <param name="opCode"></param>
        /// <param name="reason"></param>
        internal protected void Closing ( SocketAsyncEventArgs ioEventArgs, sbyte opCode = OpCode.Close, string reason = "" ) {
            bool needClose = true;
            var dataToken = ( DataToken ) ioEventArgs.UserToken;
            try {
                if ( opCode != OpCode.Empty ) {
                    CloseHandshake ( dataToken.Socket, reason );
                }
                if ( ioEventArgs.AcceptSocket != null ) {
                    ioEventArgs.AcceptSocket.Shutdown ( SocketShutdown.Both );
                }
            }
            catch ( Exception ) {
                needClose = false;
            }
            finally {
            }

            if ( needClose ) {
                //logger.InfoFormat("Socket：{0}关闭，关闭原因：SocketError：{1}。", dataToken.Socket.RemoteEndPoint, ioEventArgs.SocketError);
                try {
                    OnDisconnected ( new ConnectionEventArgs { Socket = dataToken.Socket } );
                }
                catch ( Exception ex ) {
                    OurDebug.LogErrorFormat ( "OnDisconnected error:{0}", ex );
                }
                ResetSAEAObject ( ioEventArgs );
            }
            ReleaseIOEventArgs ( ioEventArgs );
        }

        private void HandleBadAccept ( SocketAsyncEventArgs acceptEventArgs ) {
            try {
                ResetSAEAObject ( acceptEventArgs );
                acceptEventArgs.AcceptSocket = null;
            }
            catch {
            }
        }


        /// <summary>
        /// Close this instance.
        /// </summary>
        public void Dispose () {
            messagethreadout = true;

            if ( !_messageThread.Join ( 1000 ) )
                _messageThread.Abort ();

            DisposeAllSaeaObjects ();
            listenSocket.Close ();
            listenSocket = null;
        }

        private void DisposeAllSaeaObjects () {
            SocketAsyncEventArgs eventArgs;
            while ( this.ioEventArgsPool.Count > 0 ) {
                if ( !ioEventArgsPool.TryPop ( out eventArgs ) ) {
                    OurDebug.LogError ( "ioEventArgsPool empty" );
                    continue;
                }                
                ResetSAEAObject ( eventArgs );
            }
        }

        private static void ResetSAEAObject ( SocketAsyncEventArgs eventArgs ) {
            try {
                if ( eventArgs.AcceptSocket != null ) {
                    eventArgs.AcceptSocket.Close ();
                }
            }
            catch ( Exception ) {
            }
            eventArgs.AcceptSocket = null;
        }

    }
}
